package com.xinqi.modules.course.clazz.convert;

import com.xinqi.common.base.enums.YesNoEnum;
import com.xinqi.common.base.enums.YesNoNumberEnum;
import com.xinqi.common.base.utils.lambda.Lambdas;
import com.xinqi.common.base.utils.tree.TreeHelp;
import com.xinqi.common.mapstruct.CommonConvertConfig;
import com.xinqi.common.satoken.utils.LoginHelper;
import com.xinqi.modules.course.clazz.domain.ClassGroupEntity;
import com.xinqi.modules.course.clazz.dto.req.ClassGroupCreateDTO;
import com.xinqi.modules.course.clazz.dto.req.ClassGroupStudentCreateDTO;
import com.xinqi.modules.course.clazz.dto.req.ClassGroupStudentQueryDTO;
import com.xinqi.modules.course.clazz.dto.req.ClassGroupUpdateDTO;
import com.xinqi.modules.course.clazz.dto.rsp.ClassGroupResultDTO;
import com.xinqi.modules.course.clazz.dto.rsp.ClassGroupStudentResultDTO;
import com.xinqi.modules.course.clazz.dto.rsp.ClassStudentResultDTO;
import com.xinqi.modules.course.clazz.service.ClassGroupService;
import com.xinqi.modules.course.clazz.service.ClassGroupStudentService;
import com.xinqi.modules.course.clazz.service.ClassStudentService;
import com.xinqi.modules.course.course.enums.group.GroupCreatedTypeEnum;
import org.apache.commons.collections4.CollectionUtils;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 班级分组表转换
 *
 * @author: system
 * @date: 2023/01/17
 */
@Mapper(config = CommonConvertConfig.class)
public abstract class ClassGroupConvert {

    @Lazy
    @Autowired
    private ClassGroupStudentService classGroupStudentService;
    @Lazy
    @Autowired
    private ClassStudentService classStudentService;
    @Lazy
    @Autowired
    private ClassGroupService classGroupService;

    public abstract ClassGroupEntity create(ClassGroupCreateDTO s);

    public abstract ClassGroupEntity newEntity(ClassGroupEntity s);

    public abstract ClassGroupCreateDTO create(ClassGroupEntity s);

    public abstract ClassGroupEntity update(ClassGroupUpdateDTO s, @MappingTarget ClassGroupEntity t);

    public abstract ClassGroupEntity update(ClassGroupUpdateDTO s);

    public abstract ClassGroupResultDTO convert(ClassGroupEntity s);

    public abstract ClassGroupCreateDTO convert(ClassGroupStudentCreateDTO s);

    public abstract ClassGroupEntity convert(Long pid);

    public List<ClassGroupResultDTO> renderClassGroupTree(List<ClassGroupResultDTO> list) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }

        return TreeHelp.<ClassGroupResultDTO, Long>builder().setList(list).setChildren("children").setParent("pid").setComparator(Comparator.comparing(ClassGroupResultDTO::getCreateTime).thenComparing(ClassGroupResultDTO::getId)).build().handle(0L);
    }

    public void renderJoinedCount(ClassGroupResultDTO classGroupResultDTO) {
        //设置已进组人数
        if (CollectionUtils.isNotEmpty(classGroupResultDTO.getChildren())) {
            List<ClassGroupStudentResultDTO> studentList = new ArrayList<>();
            classGroupResultDTO.getChildren().forEach(child -> {
                if (CollectionUtils.isNotEmpty(child.getStudentList())) {
                    studentList.addAll(child.getStudentList());
                }
            });

            //设置已进组人数
            classGroupResultDTO.setInsideCount(studentList.size());
        }

        //设置组数
        classGroupResultDTO.setGroupNum(classGroupResultDTO.getChildren().size());

        //设置未进组人数
        classGroupResultDTO.setOutsideCount(classGroupResultDTO.getTotal() - classGroupResultDTO.getInsideCount());
    }

    @Transactional(rollbackFor = Exception.class)
    public void renderClassStudentCount(ClassGroupResultDTO classGroupResultDTO) {

        //设置已进组人数
        ClassGroupStudentQueryDTO queryDTO = new ClassGroupStudentQueryDTO();
        queryDTO.setClassId(classGroupResultDTO.getClassId());
        queryDTO.setPid(classGroupResultDTO.getId());
        List<ClassGroupStudentResultDTO> groupStudentList = classGroupStudentService.findStudentList(queryDTO);
        classGroupResultDTO.setInsideCount(groupStudentList.size());

        //设置未进组人数
        classGroupResultDTO.setOutsideCount(classGroupResultDTO.getTotal() - classGroupResultDTO.getInsideCount());

        //模拟用户信息
        ClassStudentResultDTO classMasterStudent = classStudentService.findVirtualClassStudentByClassIdAndUserId(classGroupResultDTO.getClassId(), LoginHelper.getUserId());
        Long studentId = Objects.isNull(classMasterStudent) ? LoginHelper.getUserId() : classMasterStudent.getStudentId();

        //设置进组状态
        renderParentJoinStatus(classGroupResultDTO, studentId);

        //设置小组数
        classGroupResultDTO.setGroupNum(Math.toIntExact(classGroupService.findChildrenGroupNum(classGroupResultDTO.getClassId(), classGroupResultDTO.getId())));

        //设置子分组人数，并在主学生所在的小组上设置进组标记
        setSonGroupStudentCount(classGroupResultDTO, groupStudentList, studentId);
    }

    private void setSonGroupStudentCount(ClassGroupResultDTO classGroupResultDTO, List<ClassGroupStudentResultDTO> groupStudentList, Long classMasterStudentId) {
        if (CollectionUtils.isNotEmpty(classGroupResultDTO.getChildren()) && CollectionUtils.isNotEmpty(groupStudentList)) {
            Map<Long, List<ClassGroupStudentResultDTO>> groupStudentListMap = new HashMap<>();

            for (ClassGroupStudentResultDTO student : groupStudentList) {
                if (!groupStudentListMap.containsKey(student.getGroupId())) {
                    List<ClassGroupStudentResultDTO> insideStudentList = new ArrayList<>();
                    insideStudentList.add(student);
                    groupStudentListMap.put(student.getGroupId(), insideStudentList);
                } else {
                    List<ClassGroupStudentResultDTO> insideStudentList = groupStudentListMap.get(student.getGroupId());
                    insideStudentList.add(student);
                }
            }

            for (ClassGroupResultDTO child : classGroupResultDTO.getChildren()) {
                if (groupStudentListMap.containsKey(child.getId())) {
                    List<ClassGroupStudentResultDTO> insideStudentList = groupStudentListMap.get(child.getId());
                    child.setInsideCount(insideStudentList.size());
                    if (CollectionUtils.isNotEmpty(insideStudentList)) {
                        Set<Long> insideStudentIdSet = insideStudentList.stream().map(ClassGroupStudentResultDTO::getStudentId).collect(Collectors.toSet());
                        if (insideStudentIdSet.contains(classMasterStudentId)) {
                            child.setJoinedStatus(YesNoEnum.YES.ordinal());
                        }
                    }
                }
            }
        }
    }

    /**
     * 这里的进组状态：当模拟学生进组时，关系用户的进组状态需要显示：已进组
     *
     * @param classGroupResultDTO  classGroupResultDTO
     * @param classMasterStudentId 班级主学生id
     */
    public void renderParentJoinStatus(ClassGroupResultDTO classGroupResultDTO, Long classMasterStudentId) {
        ClassGroupStudentResultDTO student = classGroupStudentService.findByPidAndStudentId(classGroupResultDTO.getId(), classMasterStudentId);
        if (Objects.isNull(student)) {
            classGroupResultDTO.setJoinedStatus(YesNoEnum.NO.ordinal());
        } else {
            classGroupResultDTO.setJoinedStatus(YesNoEnum.YES.ordinal());
            classGroupResultDTO.setJoinedName(student.getJoinedName());
        }
    }

    /**
     * 更新 分组排序
     * 自由分组 且 未加入 排在首位
     *
     * @param list 需要排序的集合
     */
    public List<ClassGroupResultDTO> swapGroupOrder(List<ClassGroupResultDTO> list) {
        List<ClassGroupResultDTO> beforeList = new ArrayList<>();
        List<ClassGroupResultDTO> afterList = new ArrayList<>();
        List<ClassGroupResultDTO> newList = new ArrayList<>();
        list.forEach(item -> {
            if (Objects.equals(GroupCreatedTypeEnum.FREEDOM.getCode(), item.getType())
                && Objects.equals(YesNoNumberEnum.NO.getCode(), item.getJoinedStatus())) {
                beforeList.add(item);
            } else {
                afterList.add(item);
            }
        });

        // 重组List
        newList.addAll(beforeList);
        newList.addAll(afterList);

        return newList;
    }

    public List<ClassGroupResultDTO> rendTree(List<ClassGroupResultDTO> groupList) {
        //设置树
        List<ClassGroupResultDTO> treeList = this.renderClassGroupTree(groupList);
        //设置子分组数量,并给子分组排序
        treeList.forEach(t -> {
            t.setGroupNum(t.getChildren().size());
            t.setChildren(t.getChildren());
        });
        return treeList;
    }

    public void renderChildren(ClassGroupResultDTO groupResultDTO, Long classMasterStudentId) {
        List<ClassGroupResultDTO> children = classGroupService.findListByPid(groupResultDTO.getId());
        if (CollectionUtils.isNotEmpty(children)) {
            groupResultDTO.setChildren(children);
            Lambdas.each(children, c -> this.renderStudent(c, classMasterStudentId));
        }
    }

    public void renderStudent(ClassGroupResultDTO groupResultDTO, Long classMasterStudentId) {
        ClassGroupStudentQueryDTO queryDTO = new ClassGroupStudentQueryDTO();
        queryDTO.setGroupId(groupResultDTO.getId());
        groupResultDTO.setStudentList(classGroupStudentService.findStudentList(queryDTO));
        if (CollectionUtils.isNotEmpty(groupResultDTO.getStudentList())) {
            Set<Long> studentIdList = groupResultDTO.getStudentList().stream().map(ClassGroupStudentResultDTO::getStudentId).collect(Collectors.toSet());
            if (studentIdList.contains(classMasterStudentId)) {
                groupResultDTO.setJoinedStatus(YesNoEnum.YES.ordinal());
            }
        }
    }
}
